<?php

namespace App\Http\Controllers\Token;

use Carbon\Carbon;
use Biz\Resources\TokenResource;
use Biz\Services\App\AppService;
use Lumen\Passport\LumenPassport;
use Lumen\Core\Standards\stdToken;
use Biz\Constants\App\AppConstants;
use Biz\Services\App\AppSiteService;
use Illuminate\Support\Facades\Cache;
use Lcobucci\JWT\Parser as JwtParser;
use Biz\Services\Passport\ClientService;
use Lumen\Security\Token\AppTokenSecurity;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response as Psr7Response;
use Biz\Services\Passport\AccessTokenService;
use League\OAuth2\Server\AuthorizationServer;
use Biz\Requests\Passport\IssueSiteTokenRequest;
use Lumen\Http\Resources\Json\DataResourceResponse;

/**
 * AppTokenController.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class AppTokenController extends Controller
{
    /**
     * @var mixed
     */
    protected $appService;

    /**
     * @var mixed
     */
    protected $appSiteService;

    /**
     * @var mixed
     */
    protected $clientService;

    /**
     * @var mixed
     */
    protected $accessTokenService;

    /**
     * The authorization server.
     *
     * @var \League\OAuth2\Server\AuthorizationServer
     */
    protected $server;

    /**
     * The JWT parser instance.
     *
     * @var \Lcobucci\JWT\Parser
     */
    protected $jwt;

    /**
     * SiteController constructor.
     *
     * @param AppService          $appService
     * @param AppSiteService      $appSiteService
     * @param ClientService       $clientService
     * @param AccessTokenService  $accessTokenService
     * @param AuthorizationServer $server
     * @param JwtParser           $jwt
     */
    public function __construct(AppService $appService,
                                AppSiteService $appSiteService,
                                ClientService $clientService,
                                AccessTokenService $accessTokenService,
                                AuthorizationServer $server,
                                JwtParser $jwt)
    {
        $this->appService         = $appService;
        $this->appSiteService     = $appSiteService;
        $this->clientService      = $clientService;
        $this->accessTokenService = $accessTokenService;
        $this->jwt                = $jwt;
        $this->server             = $server;

        // oauth scope
        //$this->middleware('scope:user_client');
    }

    /**
     * Authorize a client to access the user's account.
     *
     * @param IssueSiteTokenRequest $request
     *
     * @return DataResourceResponse
     */
    public function issueToken(IssueSiteTokenRequest $request)
    {
        // Get parameter
        $appId     = $request->get('app_id');
        $appSecret = $request->get('app_secret');

        // Overwrite password grant at the last minute to add support for customized TTLs
//        $now            = Carbon::now();
        $expiresAt      = Carbon::now()->addHour(2);
//        $accessTokenTTL = $now->diff($expiresAt);
        $accessTokenTTL = new \DateInterval('P2Y'); //PT2H
        $this->server->enableGrantType(
            LumenPassport::makeClientCredentialsGrant(), $accessTokenTTL
        );

        // Cache result
        $key      = sprintf('App.AccessToken.%s', $appId);
        $stdToken = Cache::remember($key, $expiresAt, function () use ($appId, $appSecret, $expiresAt) {
            // Get OAuth Client
            $oauthClient = $this->clientService->getClientByAppIdAndAppSecret($appId, $appSecret);

            // Get App
            $app = $this->appService->getAppByOAuthClient($oauthClient);

            switch ($app->type) {
                case AppConstants::TYPE_WEB_SITE:
                    // Get App Site
                    $appSite = $this->appSiteService->getSiteByApp($app);
                    break;
            }

            // Handle OAuth parameter
            $oauthRequestParams = $this->accessTokenService->handleAppTokenRequestParameters($oauthClient);

            /** @var ServerRequestInterface $psrRequest */
            $psrRequest = app(ServerRequestInterface::class);

            // Generate Psr Request
            $psrRequest = $psrRequest->withParsedBody($oauthRequestParams);

            // Get OAuth Response
            $response =$this->server->respondToAccessTokenRequest($psrRequest, new Psr7Response);

            // Converts to array
            $payload = json_decode($response->getBody()->__toString(), true);
            unset($payload['token_type']);

            // Handle Expires In
//            $expiresIn             = Carbon::now()->addSeconds($payload['expires_in']);
//            $payload['expires_in'] = $expiresIn->getTimestamp(); //->getTimestamp();

            $security = new AppTokenSecurity($oauthClient->secret);

            $stdToken = new stdToken();
            $stdToken->setExpiresIn($payload['expires_in'])
                ->setAuthToken($payload['access_token'])
                ->setAuthorizeToken($security->encrypt($app->id));

            return $stdToken;
        });

        return new TokenResource($stdToken);
    }

    //    /**
//     * Authorize a client to access the user's account.
//     *
//     * @param IssueSiteTokenRequest $request
//     *
//     * @return DataResourceResponse
//     */
//    public function issueToken(IssueSiteTokenRequest $request)
//    {
//        $appId     = $request->get('app_id');
//        $appSecret = $request->get('app_secret');
//
//        $now            = Carbon::now();
//        $expiresAt      = Carbon::now()->addDay(30);
//        $accessTokenTTL = $now->diff($expiresAt);
//
//        $cacheKey     = sprintf('Site.Paseto.AccessToken.%s', $appId);
//        $payload      = Cache::remember($cacheKey, $accessTokenTTL, function () use ($appId, $appSecret, $expiresAt) {
//            $appSite = $this->appSiteService->getSiteByAppIdAndAppSecret($appId, $appSecret);
//
//            $security = new AppTokenSecurity();
//            $accessToken = $security->encrypt($appSite->id);
//
//            $payload = [
//                'expires_in'   => $expiresAt->getTimestamp(),
//                'access_token' => $accessToken,
//            ];
//
//            return $payload;
//        });
//
//        return new DataResourceResponse($payload);
//    }
}
